package com.zealcomm.ivcscustomer.activity

import android.content.Context
import android.content.Intent
import android.hardware.camera2.CameraManager
import android.os.Bundle
import android.view.View
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import com.bumptech.glide.Glide
import com.zco.util.ExceptionUtil
import com.zco.util.LogUtil
import com.zco.util.ToastUtil
import com.zealcomm.commonui.base.BaseActivity
import com.zealcomm.ivcscustomer.R
import com.zealcomm.ivcscustomer.databinding.ActivityCameraBinding
import com.zealcomm.ivcscustomer.utils.FileProviderUtil
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

/**
 * 使用 camerax 必须打开硬件加速，否则会导致 PreView 只显示一半图像。
 */
class CameraActivity : BaseActivity() {

    private var binding: ActivityCameraBinding? = null
    private var outputDirectory: File? = null
    private var cameraExecutor: ExecutorService? = null
    private var preview: Preview? = null
    private var imageCapture: ImageCapture? = null
    private var imageAnalyzer: ImageAnalysis? = null
    private var camera: Camera? = null
    private var cameraProvider: ProcessCameraProvider? = null
    private var cameraSelector: CameraSelector? = null
    private var photoFile: File? = null
    private var placeholderType = PLACEHOLDER_TYPE_DEFAULT
    private val cameraIdList = arrayListOf<String>()
    private var usingCamera = -1

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityCameraBinding.inflate(layoutInflater)
        setContentView(binding!!.root)
        placeholderType = intent.getIntExtra(PLACEHOLDER_TYPE, PLACEHOLDER_TYPE_DEFAULT)
        when (placeholderType) {
            PLACEHOLDER_TYPE_ID_CARD_BACK -> {
                binding!!.ivPlaceholder.setImageResource(R.mipmap.img_preview_id_card_back)
            }

            PLACEHOLDER_TYPE_ID_CARD_FRONT -> {
                binding!!.ivPlaceholder.setImageResource(R.mipmap.img_preview_id_card_front)
            }
            else -> {
                binding!!.ivPlaceholder.setImageResource(R.mipmap.img_placeholder_default)
            }
        }
        val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
        cameraIdList.addAll(cameraManager.cameraIdList)
        startCamera()
        setListeners()
        outputDirectory = getOutputDirectory()
        cameraExecutor = Executors.newSingleThreadExecutor()
    }

    private fun setListeners() {
        binding!!.cameraCaptureButton.setOnClickListener {
            if (binding!!.ivChangeCamera.visibility == View.GONE) {
                binding!!.ivCapturePicture.setImageResource(android.R.color.transparent)
                binding!!.ivChangeCamera.visibility = View.VISIBLE
            } else {
                takePhoto()
            }
        }
        binding!!.ivBack.setOnClickListener { finish() }
        binding!!.ivChangeCamera.setOnClickListener {
            if (usingCamera == CameraSelector.LENS_FACING_FRONT) {
                usingCamera = CameraSelector.LENS_FACING_BACK
                cameraSelector =
                    CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK)
                        .build()
            } else {
                usingCamera = CameraSelector.LENS_FACING_FRONT
                cameraSelector =
                    CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_FRONT)
                        .build()
            }
            cameraProvider!!.unbindAll()
            // Bind use cases to camera
            camera = cameraProvider!!.bindToLifecycle(this, cameraSelector!!, preview)
            preview?.setSurfaceProvider(binding!!.viewFinder.surfaceProvider)
            imageCapture = null
        }
        binding!!.ivUpload.setOnClickListener {
            if (photoFile != null) {
                val intent = Intent()
                intent.putExtra(
                    PICTURE_PATH,
                    FileProviderUtil.getUriForFile(this@CameraActivity, photoFile)
                )
                setResult(RESULT_OK, intent)
                finish()
            } else {
                ToastUtil.showShort("请先拍照")
            }
        }
    }

    private fun startCamera() {
        if (cameraIdList.size < 1) {
            ToastUtil.showShort("未检测到摄像头，是否被其它 APP 占用？")
            finish()
            return
        }
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
        cameraProviderFuture.addListener(Runnable {
            // Used to bind the lifecycle of cameras to the lifecycle owner
            cameraProvider = cameraProviderFuture.get()
            // Preview
            preview = Preview.Builder().build()
            // Select back camera
            if (cameraIdList.contains("${CameraSelector.LENS_FACING_BACK}")) {
                usingCamera = CameraSelector.LENS_FACING_BACK
                cameraSelector =
                    CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK)
                        .build()
            } else {
                usingCamera = CameraSelector.LENS_FACING_FRONT
                cameraSelector =
                    CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_FRONT)
                        .build()
            }

            try {
                // Unbind use cases before rebinding
                cameraProvider!!.unbindAll()
                // Bind use cases to camera
                camera = cameraProvider!!.bindToLifecycle(this, cameraSelector!!, preview)
                preview?.setSurfaceProvider(binding!!.viewFinder.surfaceProvider)
            } catch (exc: Exception) {
                LogUtil.e(ExceptionUtil.getExceptionTraceString(exc))
            }
        }, ContextCompat.getMainExecutor(this))
    }

    private fun takePhoto() {
        // Get a stable reference of the modifiable image capture use case
        if (imageCapture == null) {
            imageCapture = ImageCapture.Builder().build()
            cameraProvider!!.bindToLifecycle(this, cameraSelector!!, preview, imageCapture);
        }

        // Create timestamped output file to hold the image
        photoFile = File(
            outputDirectory,
            SimpleDateFormat(
                FILENAME_FORMAT, Locale.US
            ).format(System.currentTimeMillis()) + ".jpg"
        )

        // Create output options object which contains file + metadata
        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile!!).build()

        // Setup image capture listener which is triggered after photo has
        // been taken
        imageCapture!!.takePicture(
            outputOptions,
            ContextCompat.getMainExecutor(this),
            object : ImageCapture.OnImageSavedCallback {
                override fun onError(exc: ImageCaptureException) {
                    LogUtil.e(ExceptionUtil.getExceptionTraceString(exc))
                    ToastUtil.showLong(ExceptionUtil.getExceptionTraceString(exc))
                }

                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    ToastUtil.showShort("拍摄成功")
                    Glide.with(this@CameraActivity).load(photoFile).into(binding!!.ivCapturePicture)
                    binding!!.ivChangeCamera.visibility = View.GONE
                }
            })
    }

    private fun getOutputDirectory(): File {
        val mediaDir = externalMediaDirs.firstOrNull()?.let {
            File(it, resources.getString(R.string.app_name)).apply { mkdirs() }
        }
        return if (mediaDir != null && mediaDir.exists())
            mediaDir else filesDir
    }

    companion object {
        private const val TAG = "CameraXBasic"
        private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
        val PLACEHOLDER_TYPE_DEFAULT = 0
        val PLACEHOLDER_TYPE_ID_CARD_BACK = 1
        val PLACEHOLDER_TYPE_ID_CARD_FRONT = 2
        val PLACEHOLDER_TYPE = "placeholder_type"
        val PICTURE_PATH = "picture_path"
    }
}